#pragma once

#include "SurfaceMeshModel.h"
#include "NanoflannKdTree.h"
#include "SymmetryVoter.h"
#include "Sampler.h"

#include "CustomDrawObjects.h"

class SymmetryDetector : public QObject
{
	Q_OBJECT

public:
	SymmetryDetector(SurfaceMeshModel* src_mesh);
	~SymmetryDetector();

public:
	SurfaceMeshModel			*mesh;

	std::vector<Sample>			feature_samples, base_samples;
	NanoflannKdTree3d			*feature_kdtree, *base_kdtree;

	std::vector<PointSignature>	point_signatures;
	std::vector<PointSignature> pruned_point_signatures;

	NanoflannKdTree2d*			pairing_kdtree;
	std::vector<SymmetryVoter>	sym_voters;

	// reflections
	std::vector<Vec4d>			ref_planes;
	std::vector<double>			ref_density;
	std::vector< QSet<int> >	ref_voterIDs;

public:
	// parameters
	int		numFeaturePoints;		// No. feature samples
	int		numBasePoints;			// No. base samples
	double	pairingThreshold;		// feature points with a curvature distance that is less than paringThreshold will be paired
	double	distinctiveRatio;		// feature points that are above this ratio will be skipped for pairing

public:
	// draw
	void draw();

	bool showPoints;
	bool showPointSignatures;
	bool showPrunedSignatures;
	void drawPoints();
	void drawPointSignatures();
	void drawPrunedSignatures();

	// Helpers
	void showMessage(const char* format, ...);

	// Preparation
	void				sampleGeometry();
	std::vector<Vec3d>	closestBasePoints( Vec3d query_point );
	Monge_form			mongeFormAtFeaturePoint(int fid);
	void				computePointSignatures();
	void				pruneFeaturePoints();

	void				constructPairingKdtree();
	std::vector<int>	peerPFIndices(int seed_id);
	void				generateVoters();
	void				prepareForDetection();		 

	// Reflections
	void	clusterReflections();		// cluster points in transformation space
	void	verifyReflection(int i);	// geometrically verify the resulted modes from clustering
	void	detectReflections();		// the main access for reflection detection

	// Other transformations

public:
	// test
	void test();
	void debug();
	void testPeers();

	// visual debug
	void addSignatureProperty();	// surface_mesh_info

	void visualize_kd_result( Vec3d query_point );
	void visualizePointTypes();
	void visualizePeers();
	void visualizeReflections();

	// debug
    std::vector< PointSoup > debug_points;
	VectorSoup debug_vectors;
	PlaneSoup debug_planes;
	void drawDebug();

signals:
	void addModelToDocument(SurfaceMeshModel *m);
	void showStatusMessage(char* msg);
};

